package org.duoyi.striver.gui.controller;

import ch.qos.logback.classic.Level;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.NumberUtil;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Paint;
import javafx.util.Callback;
import lombok.extern.slf4j.Slf4j;
import org.duoyi.striver.consts.TaskEnum;
import org.duoyi.striver.gui.TaskItem;
import org.duoyi.striver.service.BootstrapService;
import org.duoyi.striver.service.Task;
import org.duoyi.striver.service.TaskChainItem;
import org.duoyi.striver.service.TaskPost;
import org.duoyi.striver.service.post.LineupPost;
import org.duoyi.striver.service.post.SkillPost;

import java.lang.reflect.Proxy;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
public class SideBarController {

    private static SideBarController INSTANCE;

    private static DateTimeFormatter LOG_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");


    int index;
    TaskItem data;


    private BootstrapService bootstrapService;

    @FXML
    private Pane container;

    @FXML
    private Button start;

    @FXML
    private Button stop;

    @FXML
    private ListView<TaskItem> taskList;

    @FXML
    private TabPane tabPane;

    @FXML
    private ListView<Label> logView;

    @FXML
    void start(ActionEvent event) {
        taskList.getItems().forEach(TaskItem::disable);
        bootstrapService = new BootstrapService(getTasks());
        //清除日志
        logView.setItems(FXCollections.observableArrayList());
        //切换到日志面板
        tabPane.getSelectionModel().select(1);
        bootstrapService.execute();
        start.setDisable(true);
        stop.setDisable(false);
    }

    @FXML
    void stop(ActionEvent event) {
        taskList.getItems().forEach(TaskItem::enable);
        bootstrapService.stop();
        start.setDisable(false);
        stop.setDisable(true);
    }

    private List<TaskChainItem> getTasks() {
        List<TaskChainItem> tasks = new ArrayList<>();
        for (TaskItem item : taskList.getItems()) {
            if (!item.getCheckBox().isSelected()) {
                continue;
            }
            TaskEnum taskEnum = TaskEnum.valueOf(item.getName());
            Task task;
            try {
                task = taskEnum.getTaskClass().newInstance();
            } catch (InstantiationException | IllegalAccessException e ) {
                String msg = String.format("初始化任务实例失败，类名【%s】", taskEnum.getTaskClass().getName());
                log.error(msg);
                throw new RuntimeException(msg);
            }

            String skill = item.getSkillBox().getValue();
            if (NumberUtil.isNumber(skill)) {
                SkillPost skillPost = new SkillPost(task, Integer.parseInt(skill));
                task = postProxy(task, skillPost);
            }

            String lineup = item.getLineupBox().getValue();
            if (NumberUtil.isNumber(lineup)) {
                LineupPost lineupPost = new LineupPost(task, Integer.parseInt(lineup));
                task = postProxy(task, lineupPost);
            }

            tasks.add(new TaskChainItem(task));
        }
        return tasks;
    }

    private static Task postProxy(Task treasureTask, TaskPost taskPost) {
        Class<?>[] interfaces = treasureTask.getClass().getInterfaces();
        Class<?>[] interfaces1 = treasureTask.getClass().getSuperclass().getInterfaces();
        Class<?>[] allInterfaces = ArrayUtil.addAll(interfaces, interfaces1);
        return (Task) Proxy.newProxyInstance(taskPost.getClass().getClassLoader(), allInterfaces, taskPost);
    }

    public static void init(SideBarController instance) {
        INSTANCE = instance;
    }

    public static SideBarController getInstance() {
        if (INSTANCE == null) {
            throw new RuntimeException("窗口未初始化");
        }
        return INSTANCE;
    }

    public void moveTo(int x, int y) {
        INSTANCE.container.getScene().getWindow().setX(x);
        INSTANCE.container.getScene().getWindow().setY(y);
    }

    public void addLog(String message, Level level) {
        String time = LocalDateTime.now().format(LOG_TIME_FORMATTER);
        Label label = new Label(time + " " + message);
        if (Level.WARN.equals(level)) {
            label.setTextFill(Paint.valueOf("orange"));
        } else if (Level.ERROR.equals(level)){
            label.setTextFill(Paint.valueOf("red"));
        }
        Platform.runLater(() -> {
            logView.getItems().add(label);
            logView.scrollTo(logView.getItems().size() - 1);
        });
    }

    @FXML
    void initialize() {
        initTaskView();
        initLogView();
    }

    private void initLogView() {
        ObservableList<Label> logs = FXCollections.observableArrayList();
        logView.setItems(logs);
    }

    private void initTaskView() {
        List<TaskItem> taskItems = new ArrayList<>();
        Set<Class<?>> taskClass = ClassUtil.scanPackage("org.duoyi.striver.service.task");
        for (Class<?> clazz : taskClass) {
            if (ClassUtil.isAbstract(clazz) && ClassUtil.isAssignable(Task.class, clazz)) {
                continue;
            }
            taskItems.add(new TaskItem(TaskEnum.getByClass((Class<? extends Task>) clazz).name()));
        }
        List<TaskItem> sortItems = taskItems.stream()
                .sorted((x, y) -> {
                    if (x.getName().equals(TaskEnum.自动挖宝.name())) {
                        return 1;
                    } else if (y.getName().equals(TaskEnum.自动挖宝.name())) {
                        return -1;
                    }
                    return 0;
                }).collect(Collectors.toList());

        ObservableList<TaskItem> list = FXCollections.observableArrayList();
        list.addAll(sortItems);
        taskList.setItems(list);

        taskList.setCellFactory(new Callback<ListView<TaskItem>, ListCell<TaskItem>>() {
            int position = 0;
            TaskItem positionValue = null;
            @Override
            public ListCell<TaskItem> call(ListView<TaskItem> param) {
                Label label = new Label();
                ListCell<TaskItem> cell = new ListCell<TaskItem>() {

                    @Override
                    public void updateItem(TaskItem item, boolean empty) {
                        super.updateItem(item, empty);

                        if (!empty) {
                            label.setText(item.getName());
                            this.setGraphic(item.getBox());
                            this.setContentDisplay(ContentDisplay.RIGHT);
                        } else {
                            this.setText(null);
                            this.setGraphic(null);
                        }
                    }

                };

                //设置如何处理拖拽元素，先删除拖拽位置元素，再将其添加在拖拽位置
                cell.setOnDragDropped(event -> {
                    if(position == -1){
                        position = param.getItems().size()-1;
                    }
                    param.getItems().remove(index);
                    param.getItems().add(position, data);
                    param.getSelectionModel().select(position);
                });

                cell.setOnDragOver(event -> {
                    event.acceptTransferModes(TransferMode.MOVE);
                });
                //实时获取拖拽位置
                cell.setOnDragEntered(event -> {
                    positionValue = param.getItems().stream().filter(taskItem -> taskItem.getName().equals(label.getText())).findFirst().get();
                    position = param.getItems().indexOf(positionValue);
                    param.getFocusModel().focus(position);//得到焦点
                });
                //创建拖拽面板加入选中拖拽元素
                cell.setOnDragDetected(event -> {
                    index = param.getFocusModel().getFocusedIndex();
                    data = param.getFocusModel().getFocusedItem();
                    Dragboard db = cell.startDragAndDrop(TransferMode.MOVE);
                    ClipboardContent content = new ClipboardContent();
                    content.putString(data.getName());
                    db.setContent(content);
                });

                return cell;
            }
        });
        //设置单元格尺寸 s
        taskList.setFixedCellSize(30);
    }
}
